﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.ExportToRTR.CApExportToRTRRobotsExporter
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using DnProcessSimulateCommands.ExportToRTR.YAML;
using EngineeringInternalExtension;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Tecnomatix.Engineering;


namespace DnProcessSimulateCommands.ExportToRTR{

/// <summary>
/// 机器人导出器：
/// - 构建/复用机器人原型（RobotPrototype）并导出机器人实例（RobotInstance）
/// - 记录与机器人有关的 3D 对象（链路/补充件），供碰撞集与忽略规则使用
/// - 导出挂载对象/附着对象/导轨等补充件
/// </summary>
public class CApExportToRTRRobotsExporter : CApExportToRTRCollectionExporter<TxRobot>
{
  private Dictionary<TxRobot, CApExportToRTRRobotSupplements> m_supplements;
  private TxReportWriterEx m_logWriter;
  private Dictionary<string, RobotPrototype> m_robotPrototypes = new Dictionary<string, RobotPrototype>();
  private CUiExportToRTRContentDataHandler m_contentDataHandler;
  private Dictionary<string, Dictionary<string, ITxObject>> m_robotPrototypeToSourceInstanceLinks = new Dictionary<string, Dictionary<string, ITxObject>>();

  public Dictionary<TxRobot, List<TxJoint>> ExternalJoints { get; set; } = new Dictionary<TxRobot, List<TxJoint>>();

  internal Dictionary<ITxObject, TxRobot> ObjectsWith3DOfRobot { get; } = new Dictionary<ITxObject, TxRobot>();

  internal Dictionary<ITxObject, TxRobot> ChildernWith3DOfRobot { get; } = new Dictionary<ITxObject, TxRobot>();

  internal Dictionary<TxRobot, Dictionary<string, ITxObject>> RobotToProtoLinks { get; } = new Dictionary<TxRobot, Dictionary<string, ITxObject>>();

  public CApExportToRTRRobotsExporter(
    CUiExportToRTRContentDataHandler dataHandler,
    TxReportWriterEx logWriter)
  {
    this.m_logWriter = logWriter;
    this.m_supplements = new Dictionary<TxRobot, CApExportToRTRRobotSupplements>();
    this.m_contentDataHandler = dataHandler;
  }

  /// <summary>
  /// 入口：导出当前缓冲的所有机器人。
  /// </summary>
  public override void Export(CApExportToRTRXmlWriter writer, string path, string worldLink)
  {
    this.ExportRobots(path);
  }

  /// <summary>
  /// 遍历所有机器人，
  /// - 将姿态暂清零后生成机器人原型（若不存在则创建），并输出机器人实例
 /// - 收集有3D几何的相关对象映射
  /// - 如存在补充件（工具/设备/附着/导轨），一并导出
  /// </summary>
  private void ExportRobots(string path)
  {
    foreach (TxRobot txRobot in this.Objects)
    {
      using (TxPoseData currentPose = txRobot.CurrentPose)
      {
        ((IEnumerable<ITxObject>) txRobot.DrivingJoints).ToList<ITxObject>().ForEach((Action<ITxObject>) (x => (x as TxJoint).CurrentValue = 0.0));
        CApExportToRTRRobotPrototype.BlankSubDevices(txRobot);
        string componentPath = TxComponentEx.GetComponentPath((ITxComponent) txRobot, false);
        if (!this.m_robotPrototypes.ContainsKey(componentPath))
        {
          CApExportToRTRRobotPrototype rtrRobotPrototype = new CApExportToRTRRobotPrototype(txRobot, path, this.m_logWriter);
          RobotPrototype robotPrototype = rtrRobotPrototype.Export();
          this.m_robotPrototypes.Add(componentPath, robotPrototype);
          this.m_robotPrototypeToSourceInstanceLinks.Add(componentPath, rtrRobotPrototype.ExportedLinksWith3DNameToObjectMap);
        }
        new CApExportToRTRRobotInstance(txRobot, this.m_robotPrototypes[componentPath], this.m_logWriter).Export();
        Dictionary<string, ITxObject> sourceInstanceLink = this.m_robotPrototypeToSourceInstanceLinks[componentPath];
        this.AddRelevantLinksToRobotChildrenWith3D(txRobot, sourceInstanceLink);
        if (this.m_supplements.ContainsKey(txRobot))
          this.ExportRobotSupplements(this.m_supplements[txRobot], txRobot, path);
        txRobot.CurrentPose = currentPose;
      }
    }
  }

  /// <summary>
  /// 将原型中的链路名称映射回源实例对象，登记为“机器人子对象有3D”。
  /// </summary>
  private void AddRelevantLinksToRobotChildrenWith3D(
    TxRobot robot,
    Dictionary<string, ITxObject> linkNameToObjectMap)
  {
    foreach (ITxObject link in (Collection<ITxObject>) robot.Links)
    {
      if (linkNameToObjectMap.ContainsKey(link.Name))
        this.ChildernWith3DOfRobot.Add(link, robot);
    }
    this.RobotToProtoLinks.Add(robot, linkNameToObjectMap);
  }

  /// <summary>
  /// 导出与机器人关联的补充数据（挂载设备/对象、附着设备/对象、导轨）。
  /// </summary>
  private void ExportRobotSupplements(
    CApExportToRTRRobotSupplements robotSupplements,
    TxRobot robot,
    string path)
  {
    this.ExportRobotMountedObject<ITxDevice>((CApExportToRTRCollectionExporter<ITxDevice>) robotSupplements.MountedDevices, robot, path);
    this.ExportRobotMountedObject<ITxObject>((CApExportToRTRCollectionExporter<ITxObject>) robotSupplements.MountedObjects, robot, path);
    this.ExportRobotAttachedDevices(robotSupplements.AttachedDevices, robot, path);
    this.ExportRobotAttachedObjects(robotSupplements.AttachedObjects, robot, path);
    if (robotSupplements.RailAttachments == null)
      return;
    this.ExportRobotRails(robotSupplements.RailAttachments, robot, path);
  }

  /// <summary>
  /// 导出机器人导轨与其附着对象。
  /// </summary>
  private void ExportRobotRails(
    Tuple<ITxDevice, HashSet<ITxLocatableObject>> railAttachments,
    TxRobot robot,
    string path)
  {
    ITxDevice rail = railAttachments.Item1;
    new CApExportToRTRRobotSupplementRail(rail, (rail as ITxLocatableObject).AttachmentParent, robot, path, railAttachments.Item2).Export();
  }

  /// <summary>
  /// 计算附着对象相对于附着父的变换；若父为链路且存在父关节，则叠加链路到集合的相对变换。
  /// </summary>
  public static TxTransformation GetOrigin(
    ITxLocatableObject obj,
    ITxLocatableObject attachmentParent)
  {
    TxTransformation origin = obj.GetLocationRelativeToObject(attachmentParent);
    ITxObjectCollection collection = ((ITxObject) attachmentParent).Collection;
    if (attachmentParent is TxKinematicLink && TxJoint.op_Inequality((attachmentParent as TxKinematicLink).ParentJoint, (ITxObject) null))
      origin = TxTransformation.op_Multiply(attachmentParent.GetLocationRelativeToObject(collection as ITxLocatableObject), origin);
    return origin;
  }

  /// <summary>
  /// 导出“附着设备”：
  /// - 工具：走 mounted 逻辑；
  /// - 伺服枪等特殊外部轴工具：按外部轴补充件导出；
  /// - 其他设备：按附着对象导出。
  /// 同时处理 FUPA 非碰撞实体的可见性切换。
  /// </summary>
  private void ExportRobotAttachedDevices(
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachedDevices,
    TxRobot robot,
    string path)
  {
    TxObjectList<ITxDevice> coupledFupa = TxRobotEx.GetCoupledFupa((ITxRobot) robot);
    foreach (KeyValuePair<ITxLocatableObject, HashSet<ITxLocatableObject>> attachedDevice in attachedDevices)
    {
      foreach (ITxLocatableObject attachedObj in attachedDevice.Value)
      {
        if (attachedObj is ITxTool)
          this.ExportMountedObject<ITxLocatableObject>(attachedObj, robot, path);
        else if (((Collection<ITxDevice>) coupledFupa).Contains(attachedObj as ITxDevice))
          (attachedObj as ITxDisplayableObject).Blank();
        else
          this.ExportRobotAttachedObject(attachedObj, attachedDevice.Key, robot, path);
      }
    }
  }

  /// <summary>
  /// 导出“挂载对象/设备”：按名称排序后逐个导出，并登记其 3D 对象。
  /// </summary>
  private void ExportRobotMountedObject<T>(
    CApExportToRTRCollectionExporter<T> mountedObjects,
    TxRobot robot,
    string path)
  {
    HashSet<T> objects = mountedObjects.Objects;
    SortedList<string, T> sortedList = new SortedList<string, T>(objects.Count);
    foreach (T obj in objects)
      sortedList.Add(TxObjectEx.GetUniqueNameForRTR((object) obj as ITxObject, false), obj);
    foreach (T obj in (IEnumerable<T>) sortedList.Values)
      this.ExportMountedObject<T>(obj, robot, path);
  }

  /// <summary>
  /// 导出单个挂载对象：
  /// - 工具外部轴（伺服枪）按详细级别装载几何再导出
  /// - 导出后恢复显示/装载级别
  /// - 记录导出的3D对象（自身与子）映射到机器人
  /// </summary>
  private void ExportMountedObject<T>(T item, TxRobot robot, string path)
  {
    if ((object) item is ITxTool)
      ((IEnumerable<ITxObject>) ((object) item as ITxTool).NonCollidingEntities).ToList<ITxObject>().ForEach((Action<ITxObject>) (x => (x as ITxDisplayableObject).Blank()));
    bool shouldLoadDetailed = false;
    CApExportToRTRRobotSupplement rtrRobotSupplement = !((object) item is ITxDevice) || !this.IsToolExternalAxis((object) item as ITxDevice, robot, out shouldLoadDetailed) ? new CApExportToRTRRobotSupplement((object) item as ITxLocatableObject, ((object) item as ITxLocatableObject).AttachmentParent, robot, path) : (CApExportToRTRRobotSupplement) new CApExportToRTRRobotSupplementExternalAxis((object) item as ITxDevice, ((object) item as ITxLocatableObject).AttachmentParent, robot, path);
    if (shouldLoadDetailed)
      (((object) item as ITxStorable).StorageObject as TxLibraryStorage).Reload((TxRepresentationLevel) 5);
    rtrRobotSupplement.Export();
    this.AddExported3DObjects(robot, rtrRobotSupplement.ObjectsWith3D);
    this.AddExported3DObjects(robot, rtrRobotSupplement.ChildrenWith3D);
    if (shouldLoadDetailed)
      (((object) item as ITxStorable).StorageObject as TxLibraryStorage).Reload((TxRepresentationLevel) 4);
    if (!((object) item is ITxTool))
      return;
    ((IEnumerable<ITxObject>) ((object) item as ITxTool).NonCollidingEntities).ToList<ITxObject>().ForEach((Action<ITxObject>) (x => (x as ITxDisplayableObject).Display()));
  }

  /// <summary>
  /// 导出“附着对象”：相对于键（父）计算定位并导出，
  /// 记录“忽略碰撞”候选对象列表（供后续规则生成）。
  /// </summary>
  private void ExportRobotAttachedObjects(
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachedObjects,
    TxRobot robot,
    string path)
  {
    foreach (KeyValuePair<ITxLocatableObject, HashSet<ITxLocatableObject>> attachedObject in attachedObjects)
    {
      List<ITxObject> collection = new List<ITxObject>();
      ITxLocatableObject key = attachedObject.Key;
      SortedList<string, ITxLocatableObject> sortedList = new SortedList<string, ITxLocatableObject>(attachedObject.Value.Count);
      foreach (ITxLocatableObject itxLocatableObject in attachedObject.Value)
        sortedList.Add(TxObjectEx.GetUniqueNameForRTR((ITxObject) itxLocatableObject, false), itxLocatableObject);
      foreach (ITxLocatableObject attachedObj in (IEnumerable<ITxLocatableObject>) sortedList.Values)
      {
        this.ExportRobotAttachedObject(attachedObj, key, robot, path);
        collection.Add((ITxObject) attachedObj);
      }
      if (CApExportToRTRYamlMgr.Instance.IgnoredObjects.ContainsKey(robot))
        CApExportToRTRYamlMgr.Instance.IgnoredObjects[robot].Item2.AddRange((IEnumerable<ITxObject>) collection);
      else
        CApExportToRTRYamlMgr.Instance.IgnoredObjects[robot] = new Tuple<List<ITxObject>, List<ITxObject>>(new List<ITxObject>(), collection);
    }
  }

  /// <summary>
  /// 导出单个附着对象（修正父节点至 YAML 模型可识别的层级）。
  /// </summary>
  private void ExportRobotAttachedObject(
    ITxLocatableObject attachedObj,
    ITxLocatableObject attachmentParent,
    TxRobot robot,
    string path)
  {
    attachmentParent = this.ReComputeAttachmentParent(attachmentParent, robot);
    CApExportToRTRRobotSupplement rtrRobotSupplement = new CApExportToRTRRobotSupplement(attachedObj, attachmentParent, robot, path);
    rtrRobotSupplement.Export();
    this.AddExported3DObjects(robot, rtrRobotSupplement.ObjectsWith3D);
  }

  /// <summary>
  /// 修正附着父节点：沿着物理层级上溯，直至 YAML 可识别的父层（Robot 集合内）。
  /// </summary>
  private ITxLocatableObject ReComputeAttachmentParent(
    ITxLocatableObject attachmentParent,
    TxRobot robot)
  {
    while (attachmentParent != null && attachmentParent != TxApplication.ActiveDocument.PhysicalRoot && CApExportToRTRRobotSupplement.GetYamlParent(attachmentParent, (ITxObjectCollection) robot) == null)
      attachmentParent = attachmentParent.AttachmentParent;
    return attachmentParent;
  }

  /// <summary>
  /// 记录“挂载对象”。
  /// </summary>
  internal void AddMountedObject(TxRobot robot, ITxObject tool)
  {
    if (tool == null)
      return;
    if (!this.m_supplements.ContainsKey(robot))
      this.m_supplements.Add(robot, new CApExportToRTRRobotSupplements());
    this.m_supplements[robot].MountedObjects.Add(tool);
  }

  /// <summary>
  /// 记录“挂载设备”。
  /// </summary>
  internal void AddMountedDevice(TxRobot robot, ITxDevice device)
  {
    if (device == null)
      return;
    if (!this.m_supplements.ContainsKey(robot))
      this.m_supplements.Add(robot, new CApExportToRTRRobotSupplements());
    this.m_supplements[robot].MountedDevices.Add(device);
  }

  /// <summary>
  /// 记录机器人导轨设备。
  /// </summary>
  internal void AddRail(TxRobot robot, ITxDevice rail)
  {
    if (rail == null)
      return;
    if (!this.m_supplements.ContainsKey(robot))
      this.m_supplements.Add(robot, new CApExportToRTRRobotSupplements());
    this.m_supplements[robot].RailAttachments = new Tuple<ITxDevice, HashSet<ITxLocatableObject>>(rail, new HashSet<ITxLocatableObject>());
  }

  /// <summary>
  /// 获取机器人导轨设备。
  /// </summary>
  internal ITxDevice GetRail(TxRobot robot)
  {
    ITxDevice rail = (ITxDevice) null;
    if (this.m_supplements.ContainsKey(robot))
      rail = this.m_supplements[robot].RailAttachments?.Item1;
    return rail;
  }

  /// <summary>
  /// 记录导轨附着对象集合。
  /// </summary>
  internal void SetRailAttachedObjects(TxRobot robot, HashSet<ITxLocatableObject> attachedObjects)
  {
    this.m_supplements[robot].RailAttachments = new Tuple<ITxDevice, HashSet<ITxLocatableObject>>(this.m_supplements[robot].RailAttachments.Item1, attachedObjects);
  }

  /// <summary>
  /// 记录机器人附着对象映射。
  /// </summary>
  internal void SetRobotAttachedObjects(
    TxRobot robot,
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachedObjects)
  {
    if (!this.m_supplements.ContainsKey(robot))
      this.m_supplements.Add(robot, new CApExportToRTRRobotSupplements());
    this.m_supplements[robot].AttachedObjects = attachedObjects;
  }

  /// <summary>
  /// 记录机器人附着设备映射。
  /// </summary>
  internal void SetRobotAttachedDevices(
    TxRobot robot,
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachedDevices)
  {
    if (!this.m_supplements.ContainsKey(robot))
      this.m_supplements.Add(robot, new CApExportToRTRRobotSupplements());
    this.m_supplements[robot].AttachedDevices = attachedDevices;
  }

  /// <summary>
  /// 查询某 3D 对象所属的机器人。
  /// </summary>
  internal TxRobot RobotOf3DExportedObject(ITxObject obj)
  {
    TxRobot txRobot;
    this.ObjectsWith3DOfRobot.TryGetValue(obj, out txRobot);
    return txRobot;
  }

  /// <summary>
  /// 判断是否为“工具外部轴”（例如伺服枪），并输出是否需要加载详细几何。
  /// 依据 ContentDataHandler 中的机器人/工具数据判断。
  /// </summary>
  private bool IsToolExternalAxis(ITxDevice device, TxRobot robot, out bool shouldLoadDetailed)
  {
    bool flag = false;
    shouldLoadDetailed = false;
    CApExportToRTRRobotToolData rtrRobotToolData;
    CApExportToRTRRobotData exportToRtrRobotData;
    if (this.m_contentDataHandler.DataOfTools.TryGetValue(device, out rtrRobotToolData) && this.m_contentDataHandler.DataOfRobots.TryGetValue((ITxRobot) robot, out exportToRtrRobotData))
    {
      shouldLoadDetailed = rtrRobotToolData.IsGunWithAvailableKinematicFunctions && rtrRobotToolData.ShouldLoadDetailed;
      flag = rtrRobotToolData.IsServoGun && rtrRobotToolData.IsExternalAxis && !rtrRobotToolData.IsGunWithLoops && rtrRobotToolData.IsGunWithAvailableKinematicFunctions && !exportToRtrRobotData.HasUnSupportedExternalAxes;
    }
    return flag;
  }

  /// <summary>
  /// 将导出的 3D 对象记录到“对象→机器人”的映射。
  /// </summary>
  private void AddExported3DObjects(TxRobot robot, List<ITxObject> objectsWithExported3D)
  {
    objectsWithExported3D.ForEach((Action<ITxObject>) (obj => this.ObjectsWith3DOfRobot.Add(obj, robot)));
  }

  /// <summary>
  /// 将导出的 3D 子对象记录到“子对象→机器人”的映射。
  /// </summary>
  private void AddExported3DChildren(TxRobot robot, List<ITxObject> childrenWithExported3D)
  {
    childrenWithExported3D.ForEach((Action<ITxObject>) (obj => this.ChildernWith3DOfRobot.Add(obj, robot)));
  }
}
